﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
using System.IO;

namespace DaliUsb
{
  internal static class HID
  {
    /// <summary>
    /// Gets the GUID that Windows uses to represent HID class devices
    /// </summary>
    /// <returns>The GUID that Windows uses to represent HID class devices</returns>
    internal static Guid GetHidGuid()
    {
      Guid hidGuid;

      hidGuid = new Guid();
      HidD_GetHidGuid(ref hidGuid);
      return hidGuid;
    }

    internal static HIDCaps GetHidCaps(string devicePath)
    {
      SafeFileHandle handle;
      IntPtr lpData;
      HIDCaps caps;
      //FileStream fs;

      // Create the file from the device path
      handle = Kernel32.CreateFile(devicePath, FileAccess.ReadWrite, FileShare.None, IntPtr.Zero, FileMode.Open, EFileAttributes.Overlapped, IntPtr.Zero);
      
      if (!handle.IsInvalid)	// if the open worked...
      {
        byte[] command = new byte[64];
        command[0] = 0x10;
        command[1] = 0x83;
        command[5] = 0xF0;
        command[7] = 0x02;

        int written = 0;

        Kernel32.WriteFile(handle, ref command[0], command.Length, ref written, 0); 


        if (HidD_GetPreparsedData(handle, out lpData))	// get windows to read the device data into an internal buffer
        {
          try
          {
            HidP_GetCaps(lpData, out caps);	// extract the device capabilities from the internal buffer
     

            //fs = new FileStream(handle, FileAccess.ReadWrite, 64, true);

           

            byte[] reply = new byte[caps.InputReportByteLength];

            //fs.BeginRead(reply, 0, reply.Length, new AsyncCallback(ReadCompleted), null);

            //fs.Write(command, 0, command.Length);
            
         HidD_FreePreparsedData(ref lpData);	// before we quit the funtion, we must free the internal buffer reserved in GetPreparsedData

            return caps;

            
            //m_nInputReportLength = caps.InputReportByteLength;	// get the input...
            //m_nOutputReportLength = caps.OutputReportByteLength;	// ... and output report lengths
            //m_oFile = new FileStream(m_hHandle, FileAccess.Read | FileAccess.Write, true, m_nInputReportLength, true);	// wrap the file handle in a .Net file stream
            //BeginAsyncRead();	// kick off the first asynchronous read
          }
          finally
          {
            HidD_FreePreparsedData(ref lpData);	// before we quit the funtion, we must free the internal buffer reserved in GetPreparsedData
            handle.Close();
          }
        }
        else	// GetPreparsedData failed? Chuck an exception
        {
          throw new ApplicationException(string.Format("HidD_GetPreparsedData failed. WinEr:{0:X8}", Marshal.GetLastWin32Error()));
        }
      }
      else	// File open failed? Chuck an exception
      {
        handle.Close();
        throw new ApplicationException(string.Format("CreateFile failed. WinEr:{0:X8}", Marshal.GetLastWin32Error()));
      }
    }

    public static void WriteCompleted(IAsyncResult iResult)
    {
      Console.WriteLine("Write completed");
    }

    public static void ReadCompleted(IAsyncResult iResult)
    {
      Console.WriteLine("Read completed");
    }

    /// <summary>
    /// Gets the GUID that Windows uses to represent HID class devices
    /// </summary>
    /// <param name="hidGuid">A ref parameter to take the Guid</param>
    [DllImport("hid.dll", SetLastError = true)]
    private static extern void HidD_GetHidGuid(ref Guid hidGuid);


    /// <summary>
    /// Gets details from an open device. Reserves a block of memory which must be freed.
    /// </summary>
    /// <param name="hFile">Device file handle</param>
    /// <param name="lpData">Reference to the preparsed data block</param>
    /// <returns></returns>
    [DllImport("hid.dll", SetLastError = true)]
    private static extern bool HidD_GetPreparsedData(SafeFileHandle hFile, out IntPtr lpData);

    /// <summary>
    /// Frees the memory block reserved above.
    /// </summary>
    /// <param name="pData">Reference to preparsed data returned in call to GetPreparsedData</param>
    /// <returns></returns>
    [DllImport("hid.dll", SetLastError = true)]
    private static extern bool HidD_FreePreparsedData(ref IntPtr pData);
    
    /// <summary>
    /// Gets a device's capabilities from the preparsed data.
    /// </summary>
    /// <param name="lpData">Preparsed data reference</param>
    /// <param name="oCaps">HidCaps structure to receive the capabilities</param>
    /// <returns>True if successful</returns>
    [DllImport("hid.dll", SetLastError = true)]
    private static extern int HidP_GetCaps(IntPtr lpData, out HIDCaps oCaps);


  }
}
